﻿using System;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using O1.Kernel.Storage.Transactions;

namespace Tests.O1.Kernel.Storage.Transactions
{
    [TestClass]
    public class MultiVersionOfTTests
    {
        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionInitializedWithEndAsInfinityValueByDefault()
        {
            new MultiVersion<object>(1234, new object()).End.Should().Be(MultiVersion.Infinity);
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionInitializedWithExpiredFalse()
        {
            new MultiVersion<object>(1234, new object()).Expired.Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionGetHashcodeIsConsistent()
        {
            long addTx = 1234;
            var tx = new MultiVersion<object>(addTx, new object());
            tx.GetHashCode().Should().Be(tx.GetHashCode());
            tx.GetHashCode().Should().NotBe(new MultiVersion<object>().GetHashCode());
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionObjectEqualsIsFalseComparedToNull()
        {
            ((object)new MultiVersion<object>()).Equals(null).Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionObjectEqualsIsFalseComparedToUnknownTypeIsFalse()
        {
            ((object)new MultiVersion<object>(12345, new object())).Equals("12345").Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionObjectEqualsWhenBoxedMatchesEquals()
        {
            long addTx = 1234;
            var tx = new MultiVersion<object>(addTx, new object());
            var boxed = (object)tx;

            boxed.Equals(addTx).Should().Be(addTx == tx);
            boxed.Equals(tx).Should().Be(addTx == tx);
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionMaxUncommittedValueIsNegativeOne()
        {
            MultiVersion.Infinity.Should().Be(long.MaxValue);
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionPendingIsTrueWhenAddIsPending()
        {
            var tx = new MultiVersion<object>(12345, new object());
            tx.Pending.Should().BeTrue();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionPendingIsFalseWhenAddIsCommitted()
        {
            long addTx = (1234L).AsCommitted();
            var tx = new MultiVersion<object>(addTx, new object());
            tx.Pending.Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionPendingIsTrueWhenDeleteIsPending()
        {
            long addTx = (1234L).AsCommitted();
            var tx = new MultiVersion<object>(addTx, 8888, new object());
            tx.Pending.Should().BeTrue();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionPendingIsFalseWhenDeleteIsCommitted()
        {
            long addTx = (1234L).AsCommitted();
            long deleteTx = (1238L).AsCommitted();
            var tx = new MultiVersion<object>(addTx, deleteTx, new object());
            tx.Pending.Should().BeFalse();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionEqualsIsTrueForPendingAdd()
        {
            long addTx = 1234;
            var tx1 = new MultiVersion<object>(addTx, new object());
            var tx2 = new MultiVersion<object>(addTx, new object());
            tx1.Equals(tx2).Should().BeTrue();
            tx2.Equals(tx1).Should().BeTrue();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionEqualsIsTrueForCommittedAdd()
        {
            long addTx = (1234L).AsCommitted();
            var tx1 = new MultiVersion<object>(addTx, new object());
            var tx2 = new MultiVersion<object>(addTx, new object());
            tx1.Equals(tx2).Should().BeTrue();
            tx2.Equals(tx1).Should().BeTrue();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionEqualsIsTrueForPendingDelete()
        {
            long addTx = (1234L).AsCommitted();
            long deletedTx = (long)45567;
            var tx1 = new MultiVersion<object>(addTx, deletedTx, new object());
            var tx2 = new MultiVersion<object>(addTx, deletedTx, new object());
            tx1.Equals(tx2).Should().BeTrue();
            tx2.Equals(tx1).Should().BeTrue();
        }

        [TestCategory("Tx")]
        [TestMethod, TestCategory("Unit Test")]
        public void MultiVersionEqualsIsTrueForCommittedDelete()
        {
            long addTx = (1234L).AsCommitted();
            long deletedTx = (45567L).AsCommitted();
            var tx1 = new MultiVersion<object>(addTx, deletedTx, new object());
            var tx2 = new MultiVersion<object>(addTx, deletedTx, new object()); 
            tx1.Equals(tx2).Should().BeTrue();
            tx2.Equals(tx1).Should().BeTrue();
        }

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxEqualsIsFalseForPendingAdd()
        //{
        //    ulong addTx1 = 1234;
        //    ulong addTx2 = 1236;
        //    var tx1 = new Tx(addTx1, ulong.MaxValue);
        //    var tx2 = new Tx(addTx2, ulong.MaxValue);
        //    tx1.Equals(tx2).Should().BeFalse();
        //    tx2.Equals(tx1).Should().BeFalse();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxEqualsIsFalseForCommittedAdd()
        //{
        //    ulong addTx1 = ((ulong)(1234)).EmbedStatus(TxStatus.Committed);
        //    ulong addTx2 = ((ulong)(1238)).EmbedStatus(TxStatus.Committed);
        //    var tx1 = new Tx(addTx1, ulong.MaxValue);
        //    var tx2 = new Tx(addTx2, ulong.MaxValue);
        //    tx1.Equals(tx2).Should().BeFalse();
        //    tx2.Equals(tx1).Should().BeFalse();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxEqualsIsFalseForPendingDelete()
        //{
        //    ulong addTx = ((ulong)(1234)).EmbedStatus(TxStatus.Committed);
        //    ulong deletedTx1 = (ulong)45567;
        //    ulong deletedTx2 = (ulong)45569;
        //    var tx1 = new Tx(addTx, deletedTx1);
        //    var tx2 = new Tx(addTx, deletedTx2);
        //    tx1.Equals(tx2).Should().BeFalse();
        //    tx2.Equals(tx1).Should().BeFalse();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxEqualsIsFalseForCommittedDelete()
        //{
        //    ulong addTx = ((ulong)(1234)).EmbedStatus(TxStatus.Committed);
        //    ulong deletedTx1 = ((ulong)45567).EmbedStatus(TxStatus.Committed);
        //    ulong deletedTx2 = ((ulong)45588).EmbedStatus(TxStatus.Committed);
        //    var tx1 = new Tx(addTx, deletedTx1);
        //    var tx2 = new Tx(addTx, deletedTx2);
        //    tx1.Equals(tx2).Should().BeFalse();
        //    tx2.Equals(tx1).Should().BeFalse();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxEqualityIsAsExpectedForPendingAdd()
        //{
        //    ulong addTx = 1234;
        //    var tx = new Tx(addTx, ulong.MaxValue);
        //    (addTx == tx).Should().BeTrue();
        //    (tx == addTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxEqualityIsAsExpectedForCommittedAdd()
        //{
        //    ulong addTx = ((ulong)(1234)).EmbedStatus(TxStatus.Committed);
        //    var tx = new Tx(addTx, ulong.MaxValue);
        //    (addTx == tx).Should().BeTrue();
        //    (tx == addTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxEqualityIsAsExpectedForPendingDelete()
        //{
        //    ulong addTx = ((ulong)(1234)).EmbedStatus(TxStatus.Committed);
        //    ulong deletedTx = (ulong)45567;
        //    var tx = new Tx(addTx, deletedTx);
        //    (addTx == tx).Should().BeFalse();
        //    (tx == addTx).Should().BeFalse();
        //    (deletedTx == tx).Should().BeTrue();
        //    (tx == deletedTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxEqualityIsAsExpectedForCommittedDelete()
        //{
        //    ulong addTx = ((ulong)(1234)).EmbedStatus(TxStatus.Committed);
        //    ulong deletedTx = ((ulong)45567).EmbedStatus(TxStatus.Committed);
        //    var tx = new Tx(addTx, deletedTx);
        //    (addTx == tx).Should().BeFalse();
        //    (tx == addTx).Should().BeFalse();
        //    (deletedTx == tx).Should().BeTrue();
        //    (tx == deletedTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxInequalityIsAsExpectedForPendingAdd()
        //{
        //    ulong addTx = 1234;
        //    ulong addTx1 = 1235;
        //    var tx = new Tx(addTx1, ulong.MaxValue);
        //    (addTx != tx).Should().BeTrue();
        //    (tx != addTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxInequalityIsAsExpectedForCommittedAdd()
        //{
        //    ulong addTx = ((ulong)(1234)).EmbedStatus(TxStatus.Committed);
        //    ulong addTx1 = ((ulong)(1235)).EmbedStatus(TxStatus.Committed);
        //    var tx = new Tx(addTx1, ulong.MaxValue);
        //    (addTx != tx).Should().BeTrue();
        //    (tx != addTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxInequalityIsAsExpectedForPendingDelete()
        //{
        //    ulong addTx = ((ulong)(1234)).EmbedStatus(TxStatus.Committed);
        //    ulong deletedTx = (ulong)45567;
        //    ulong deletedTx1 = (ulong)45568;
        //    var tx = new Tx(addTx, deletedTx1);
        //    (addTx != tx).Should().BeTrue();
        //    (tx != addTx).Should().BeTrue();
        //    (deletedTx != tx).Should().BeTrue();
        //    (tx != deletedTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxInequalityIsAsExpectedForCommittedDelete()
        //{
        //    ulong addTx = ((ulong)(1234)).EmbedStatus(TxStatus.Committed);
        //    ulong deletedTx = ((ulong)45567).EmbedStatus(TxStatus.Committed);
        //    ulong deletedTx1 = ((ulong)45568).EmbedStatus(TxStatus.Committed);
        //    var tx = new Tx(addTx, deletedTx1);
        //    (addTx != tx).Should().BeTrue();
        //    (tx != addTx).Should().BeTrue();
        //    (deletedTx != tx).Should().BeTrue();
        //    (tx != deletedTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxGreateWhenAddIsPendingAndGreaterThanOtherAdd()
        //{
        //    ulong addTx = 1234;
        //    ulong addTx1 = 1235;
        //    var tx = new Tx(addTx, ulong.MaxValue);
        //    (addTx1 >  tx).Should().BeTrue();
        //    (tx < addTx1).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxLessWhenAddIsPendingAndLessThanOtherAdd()
        //{
        //    ulong addTx = 1234;
        //    ulong addTx1 = 1235;
        //    var tx = new Tx(addTx1, ulong.MaxValue);
        //    (addTx < tx).Should().BeTrue();
        //    (tx > addTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxLessThanEqualToWhenAddIsPendingAndLessThanOtherAdd()
        //{
        //    ulong addTx = 1234;
        //    ulong addTx1 = 1235;
        //    var tx = new Tx(addTx1, ulong.MaxValue);
        //    (addTx <= tx).Should().BeTrue();
        //    (tx >= addTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxLessThanEqualToWhenAddIsCommittedAndLessThanOtherAdd()
        //{
        //    ulong addTx = (1234ul).EmbedStatus(TxStatus.Committed);
        //    ulong addTx1 = (1235ul).EmbedStatus(TxStatus.Committed);
        //    var tx = new Tx(addTx1, ulong.MaxValue);
        //    (addTx <= tx).Should().BeTrue();
        //    (tx >= addTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxLessThanEqualToWhenAddIsCommittedAndLessThanOtherUncommittedAdd()
        //{
        //    ulong addTx = (1234ul).EmbedStatus(TxStatus.Committed);
        //    ulong addTx1 = (1235ul).EmbedStatus(TxStatus.Pending);
        //    var tx = new Tx(addTx1, ulong.MaxValue);
        //    (addTx <= tx).Should().BeTrue();
        //    (tx >= addTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxGreaterThanEqualToWhenAddIsCommittedAndGreaterThanOtherUncommittedAdd()
        //{
        //    ulong addTx = (1236ul).EmbedStatus(TxStatus.Committed);
        //    ulong addTx1 = (1235ul).EmbedStatus(TxStatus.Pending);
        //    var tx = new Tx(addTx1, ulong.MaxValue);
        //    (addTx >= tx).Should().BeTrue();
        //    (tx <= addTx).Should().BeTrue();
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxCompareToReturns0ForEqualityWhenValueIsUncommitted()
        //{
        //    ulong addTx = (1235ul).EmbedStatus(TxStatus.Pending);
        //    ulong addTx1 = (1235ul).EmbedStatus(TxStatus.Pending);
        //    var tx = new Tx(addTx1, ulong.MaxValue);
        //    tx.CompareTo(addTx).Should().Be(0);
        //}

        //[TestCategory("Tx")]
        //[TestMethod, TestCategory("Unit Test")]
        //public void TxCompareToReturns0ForEqualityWhenValueIsCommitted()
        //{
        //    // This is the same TX ID, just in a different state:
        //    ulong addTx = (1235ul).EmbedStatus(TxStatus.Committed);
        //    ulong addTx1 = (1235ul).EmbedStatus(TxStatus.Pending);
        //    var tx = new Tx(addTx1, ulong.MaxValue);
        //    tx.CompareTo(addTx).Should().Be(0);
        //}
    }
}
